#include "XmppImpl.h"
#include "contactitem.h"

#include <vector>
#include <iostream>

Xmpp& Xmpp::instance()
{
    return XmppImpl::instance();

}

Xmpp& XmppImpl::instance()
{
    static XmppImpl xmpp;
    return xmpp;
}


XmppImpl::XmppImpl()
    :m_pDelegate(0)
{
}

XmppImpl::~XmppImpl()
{
    disconnect();

//    delete m_pClient;
    //m_pClient = 0;

    std::clog << "XmppImpl class destroyed" << std::endl;

}

void XmppImpl::disconnect()
{
    if (!isConnected())
        return;

    std::clog << "disconnecting..." << std::endl;
    m_pClient->disconnect();
    std::clog << "disconnected" << std::endl;
    m_pVcardManager.reset();
    //m_pVcardManager = 0;
    if (m_pRosterManager) {
        m_pRosterManager->removeRosterListener();
    }
//            delete m_pRosterManager;
    m_pRosterManager = 0;


}

bool XmppImpl::isConnected()
{
    if (!m_pClient)
        return false;
    if (m_pClient->state() == gloox::StateDisconnected)
        return false;
    return true;
}

bool XmppImpl::setLoginInfo(std::string loginId, std::string password)
{
    m_pClient.reset();
    m_pVcardManager.reset();

    gloox::JID jid(loginId);
    m_pClient = std::tr1::shared_ptr<gloox::Client>(new gloox::Client(jid, password));
    m_pClient->registerPresenceHandler( this );
    m_pClient->registerConnectionListener( this );
    m_pRosterManager = m_pClient->rosterManager();
    m_pRosterManager->registerRosterListener(this, false);
    m_pRosterManager->fill();
    m_pVcardManager = std::tr1::shared_ptr<gloox::VCardManager>(new gloox::VCardManager(m_pClient.get()));
    m_pPubSubManager = std::tr1::shared_ptr<gloox::PubSub::Manager>(new gloox::PubSub::Manager(m_pClient.get()));
    m_pClient->registerMessageSessionHandler( this );

    return true;

}

void XmppImpl::connect()
{
    m_pClient->connect( true );
}

void XmppImpl::requestVcard(std::string jid)
{
    if (!m_pVcardManager) {
        return;
    }

    gloox::JID id(jid);

    m_pVcardManager->fetchVCard(id, this);

}

gloox::MessageSession* XmppImpl::startChat(std::string& jid)
{
    if (!m_pClient) {
        return NULL;
    }

    gloox::JID glooxJid(jid);

     return new gloox::MessageSession( m_pClient.get(), glooxJid );

/*    XMPPSession* session = [[XMPPSession alloc]init];
    [session setSession:pSession];
    [session setXmpp:m_pDelegage];
    [[m_pDelegage sessionManager]addSession:session];
*/
    /////////////////////////////////
    // Do NOT relese session here!
    /////////////////////////////////

}

void XmppImpl::closeSession(gloox::MessageSession* pSession)
{
    m_pClient->disposeMessageSession(pSession);
}

#pragma mark -


#pragma mark *** ConnectionListener ***
void 	XmppImpl::onConnect ()
{
    m_delegateMutex.lock();
    if( !m_pDelegate )
    {
        m_delegateMutex.unlock();
        return;
    }
    m_pDelegate->onConnect();
    m_delegateMutex.unlock();



}

void 	XmppImpl::onDisconnect (gloox::ConnectionError e)
{

    m_pVcardManager.reset();
    m_pPubSubManager.reset();

    m_delegateMutex.lock();
    if( !m_pDelegate )
    {
        m_delegateMutex.unlock();
        return;
    }

    m_pDelegate->onDisconnect(e);
    m_delegateMutex.unlock();
}

void 	XmppImpl::onSessionCreateError (const gloox::Error *error)
{
    m_delegateMutex.lock();
    if( !m_pDelegate )
    {
        m_delegateMutex.unlock();
        return;
    }

    std::string errorString;
    if (error) {
        errorString = error->text();
    }
    else
    {
        errorString = "";
    }

    std::string errorMessage = errorString;
    //m_pDelegate->onSessionCreateError(errorMessage);
    m_delegateMutex.unlock();

}

bool 	XmppImpl::onTLSConnect (const gloox::CertInfo &info)
{
    return true;
}
#pragma mark -

#pragma mark *** VCard Handlers ***

void 	XmppImpl::handleVCard (const gloox::JID &jid, const gloox::VCard *vcard)
{
    if (!vcard)
        return;

    if (!jid.bare().length()) {
        return;
    }
    m_delegateMutex.lock();
    if (!m_pDelegate) {
        m_delegateMutex.unlock();
        return;
    }

    ContactItem item;// = new ContactItem;
    item.setVcard(true);
    item.setJid(jid.bare());
    item.setFullJid(jid.full());
    if (vcard->photo().binval.size())
    {
        item.setPhoto(vcard->photo().binval.c_str(), vcard->photo().binval.size());
    }
    if (vcard->photo().extval == "") {

        //NSData* imageData = [NSData dataWithBytes:vcard->photo().binval.c_str() length:vcard->photo().binval.size()];
        //item->setPhoto:imageData];
        //[imageData release];
    }
    item.setName(vcard->formattedname());

    m_pDelegate->onContactItem(item);
    //[m_pDelegage performSelectorOnMainThread:@selector(updateContact:) withObject:item waitUntilDone:NO];

    m_delegateMutex.unlock();
}
void 	XmppImpl::handleVCardResult (gloox::VCardHandler::VCardContext context, const gloox::JID &jid, gloox::StanzaError se)
{

}

#pragma mark -

#pragma mark *** RosterListener ***
void 	XmppImpl::handleRoster (const gloox::Roster &roster)
{
    m_delegateMutex.lock();
    if( !m_pDelegate )
    {
        m_delegateMutex.unlock();
        return;
    }

    gloox::Roster* pRoster = new gloox::Roster(roster);
    gloox::Roster::iterator it;
    std::vector<ContactItem> contacts;
    contacts.resize(pRoster->size());

    for (it = pRoster->begin(); it != pRoster->end(); it++) {
        std::string strKey = (*it).first;
        gloox::RosterItem* pItem = (*it).second;
        std::string strJid = pItem->jid();

        std::vector<std::string> groups;
        gloox::StringList list(pItem->groups());
        gloox::StringList::iterator it;
        for (it = list.begin(); it != list.end(); it++)
        {
            groups.push_back(*it);
        }

        std::string strName = pItem->name();
        bool online = pItem->online();

        ContactItem item;
        item.setJid(strJid);
        item.setKey(strKey);
        item.setName(strName);
        item.setOnline(online);
        item.setGroups(groups);
        contacts.push_back(item);
    }
    m_pDelegate->onContactItems(contacts);
    //[m_pDelegage performSelectorOnMainThread:@selector(updateContacts:) withObject:contacts waitUntilDone:NO];

    m_delegateMutex.unlock();
}

void 	XmppImpl::handleNonrosterPresence (const gloox::Presence &presence)
{

}
void 	XmppImpl::handleRosterError (const gloox::IQ &iq)
{

}
#pragma mark -


#pragma mark *** Message Handlers ***
void 	XmppImpl::handleMessageSession (gloox::MessageSession *session)
{
    m_pDelegate->onMessageSession(session);
    //XMPPSession* s = [[XMPPSession alloc]init];
    //[s setSession:session];
    //[s setIncomingSession:YES];
    //[s setXmpp:m_pDelegage];
    //[[m_pDelegage sessionManager] performSelectorOnMainThread:@selector(addSession:) withObject:s waitUntilDone:YES];
}

#pragma mark -

#pragma mark *** Presence Handlers ***

void 	XmppImpl::handlePresence (const gloox::Presence &presence)
{
    m_delegateMutex.lock();
    if( !m_pDelegate )
    {
        m_delegateMutex.unlock();
        return;
    }

    ContactItem item;
    item.setJid(presence.from().bare());
    item.setFullJid(presence.from().full());
    item.setStatus(presence.status());
    item.setPresence(presence.subtype());

    m_pDelegate->onContactItem(item);
    m_delegateMutex.unlock();

}
